#pragma once

#include <iostream>
#include <memory>
#include <string>
#include "./Epoller.hpp"
#include "./Socket.hpp"

using namespace EpollerModule;
using namespace NetWorkModule;

std::string EventToString(uint32_t events) {
    std::string info;
    if(events & EPOLLIN) // 表示对应的文件描述符可以读
        info += "EPOLLIN ";
    if(events & EPOLLOUT) // 表示对应的文件描述符可以写
        info += "EPOLLOUT ";
    if(events & EPOLLET) // 已经将EPOLL设置为边缘触发
        info += "EPOLLET ";
    return info;
}


class EpollServer {
    const static int backlog = 32;
    const static int gmaxevents = 64;
    public:
        EpollServer(int port) 
        :_listensock(new TcpSocket()),
        _epoller(new Epoller()), 
        _port(port),
        _isrunning(false)
        {}

        ~EpollServer() {}

        bool InitServer() {
            // 创建listensock
            _listensock->CreateSocket();
            _listensock->BindSocket(_port);
            _listensock->ListenSocket(backlog);
            std::cout << "init socket success, listensock is: " << _listensock->GetSockfd() << std::endl;
            // 创建epoll模型
            _epoller->InitEpoller();
            std::cout << "init epoller success" << std::endl;
            // 将listensock添加到epoll中
            _epoller->AddEvent(_listensock->GetSockfd(), EPOLLIN);
            return true;
        }

        bool Accepter(std::string *peerip, uint16_t *peerport) {
            // 监听事件
            int sockfd = _listensock->AcceptConnection(peerip, peerport);
            if(sockfd < 0) {
                std::cout << "accept error" << std::endl;
                return false;
            }
            // 获取链接成功，将新fd添加到epoll中
            _epoller->AddEvent(sockfd, EPOLLIN);
            return true;
        }

        int Recver(int sockfd, std::string *out) {
            char buffer[1024];
            int n = ::recv(sockfd, buffer, sizeof(buffer), 0); // 没有处理粘包问题
            if(n > 0) {
                buffer[n] = 0; // C++字符串需要以\0表示结束
                *out = buffer;
            }
            return n;
        }

        void HandlerEvent(int n) {
            // LT -> Level Triggered工作模式
            std::cout << n << "个events已经准备就绪!!!" << std::endl;
            for(int i = 0; i < n; ++i) {
                std::cout << "ready fd: " << _revs[i].data.fd << ", Event is: " << EventToString(_revs[i].events).c_str() <<std::endl;

                int sockfd = _revs[i].data.fd;
                uint32_t events = _revs[i].events;
                if(events & EPOLLIN) {
                    // 对应的文件描述符可读
                    if(sockfd == _listensock->GetSockfd()) {
                        // 有新链接到来
                        std::string clientip;
                        uint16_t clientport;
                        if(!Accepter(&clientip, &clientport))
                            continue;
                        std::cout << "accept client success, client[" << clientip << ":" << clientport << "]" << std::endl;
                    }
                    else {
                        // 正常sockfd
                        std::string message;
                        int n = Recver(sockfd, &message);
                        if(n > 0) {
                            std::cout << "client: " << message << std::endl;
                            message.resize(message.size() - strlen("\r\n")); // 针对telnet指令，每次结尾时\r\n

                            // 测试
                            std::string echo_message = "echo message: " + message + "\r\n";
                            send(sockfd, echo_message.c_str(), echo_message.size(), 0);
                        }
                        else {
                            if(n == 0) {
                                // 正常读完成
                                std::cout << "client " << sockfd << " close" << std::endl;
                            }
                            else {
                                std::cout << "client recv " << sockfd << "error" << std::endl;
                            }

                            _epoller->DelEvent(sockfd);
                            ::close(sockfd);
                        }
                    }
                }
            }
        }

        void Loop() {
            _isrunning = true;
            while(_isrunning) {
                _epoller->DebugFdList();
                int timeout = -1;   // 阻塞式
                int n = _epoller->Wait(_revs, gmaxevents, timeout);
                switch(n) {
                    case 0:
                        std::cout << "timeout..." << std::endl;
                        break;
                    case -1:
                        std::cout << "epoll wait failed!!!" << std::endl;
                        break;
                    default:
                        std::cout << "event happend..." << std::endl;
                        HandlerEvent(n);
                        break;
                }
            }

            _isrunning = false;
        }
    private:
        std::unique_ptr<TcpSocket> _listensock;     
        std::unique_ptr<Epoller> _epoller;          
        int _port;
        bool _isrunning;
        struct epoll_event _revs[gmaxevents]; 
};